const This: type = @This();
const std = @import("std");
const mem = std.mem;
const debug = std.debug;
const fmt = std.fmt;
const math = std.math;
const builtin = std.builtin;
const meta = std.meta;
// user
const Sqlite3 = @import("sqlite.zig");
const UserData = @import("userData.zig");
const time = @import("time.zig");
pub const ui = @import("ui.zig");
pub const fs = @import("./fs.zig");
const File: type = fs.File;
pub const ResStat = @import("./ResStat.zig").ResStat;
pub const SourceLocation = @import("SourceLocation.zig");
pub const Iterator = @import("./Iterator.zig");
// type
const Stmt: type = Sqlite3.Stmt;
// fn
pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){}; // <><> init
    defer debug.assert(gpa.deinit() == .ok); // <><>

    var gpa_allocator: mem.Allocator = gpa.allocator();
    const stdin = std.io.getStdIn().reader();

    try init(gpa_allocator); // <><>
    defer deinit(gpa_allocator);

    const path: [:0]const u8 = try fs.data_file.path(gpa_allocator, .@"user_data.db"); // <><>
    defer gpa_allocator.free(path);
    std.debug.print("[[src: {}]]\npath: {s}\n", .{ SourceLocation.init(@src()), path });

    var user_data: UserData = UserData.init(path) catch @panic("nb"); // <><> init
    defer user_data.deinit(); // <><> defer deinit

    while (blk: {
        debug.print("PID: {}\n", .{std.os.linux.getpid()});
        debug.print("today_days: {}\n", .{time.getDays()});

        const Do: type = enum { // operation code
            review_past,
            insert,
            review_today,
            delete,
            update_time,
            exit,

            pub fn fromInt(int: meta.Tag(@This())) @This() {
                return @enumFromInt(int);
            }
        };
        const do: Do = ui.get_ui_enum(Do, stdin);
        switch (do) {
            .review_past => user_data.reviewPast(time.getDays(), stdin),
            .insert => {
                const question: [:0]const u8 = try ui.get_ui_textByVim(gpa_allocator, "请输入问题", stdin); // <><> init
                defer gpa_allocator.free(question); // <><> deinit

                const answer: [:0]const u8 = try ui.get_ui_textByVim(gpa_allocator, "请输入答案", stdin); // <><> init
                defer gpa_allocator.free(answer); // <><> deinit

                const today_date_str: [:0]const u8 = try fmt.allocPrintZ(gpa_allocator, "{}", .{time.getDate(time.timestamp())}); // <><> init
                defer gpa_allocator.free(today_date_str); // <><> deinit
                const last_insert_rowid: i64 = user_data.insert(time.getDays(), today_date_str, question, answer) catch @panic("nb");

                debug.print("id: {}\n", .{last_insert_rowid});
            },
            .review_today => user_data.reviewToday(time.getDays(), stdin),
            .delete => a: {
                const id: i64 = id_while: while (true) : (debug.print("输入错误, 重新开始\n", .{})) {
                    debug.print("请输入id(取消请输入 0):\n", .{});
                    const id_str: []const u8 = stdin.readUntilDelimiterAlloc(gpa_allocator, '\n', math.maxInt(u8)) catch continue; // <><> init
                    defer gpa_allocator.free(id_str); // <><> deinit
                    ui.ui_clear();
                    const id: i64 = fmt.parseUnsigned(i64, id_str, 10) catch continue;
                    std.debug.print("检测到输入的内容: {}\n", .{id});
                    break :id_while id;
                };
                if (id == 0) break :a;
                user_data.delete(id) catch |err| switch (err) {
                    error.not_found => std.debug.print("{}\n", .{err}),
                    error.TestUnexpectedResult => |e| return e,
                };
            },
            .update_time => {},
            .exit => {},
        }
        break :blk do;
    } != .exit) {}
}

// static field
var option_init: *u1 = undefined;
fn init(allocator: mem.Allocator) !void {
    option_init = try allocator.create(u1);
    errdefer allocator.destroy(@This().option_init);
    try fs.init(allocator);
    errdefer fs.deinit(allocator);
}
fn deinit(allocator: mem.Allocator) void {
    defer allocator.destroy(@This().option_init);
    defer fs.deinit(allocator);
}
//
//
//
//
//
